import inspect
from typing import List, Dict, Any, Union

# 导入必要的依赖
from constant.tool_dict_config import toolDictConfig
from mcp_tools.mcpFactory import MCPFactory, logger
# 使用MCPFactory的异步方法创建连接
import asyncio
# 获取数据库会话
from config.database import get_db_session
# 在已有事件循环中，使用run_in_executor
import concurrent.futures

class MCPMixin:
    """MCP功能混入类，包含所有MCP相关的方法"""

    def get_mcp_tools_prompt_text(self) -> str:
        """
        获取格式化的MCP工具提示词文本，供子类Agent使用
        
        Returns:
            格式化的MCP工具提示词字符串
        """
        try:
            # 检查是否有MCP调用工具
            has_mcp_calling = any(tool.name in ['call_mcp_tool', 'list_mcp_services'] for tool in (self.tools or []))

            if not has_mcp_calling:
                return ""

            # 使用统一的全局工具字典信息
            global_tools_info = self.get_mcp_tools_info_from_global_dict()

            if global_tools_info.get("initialized"):
                # 从全局工具字典获取MCP信息
                used_mcp_tools = global_tools_info.get("used_mcp_tools", {})
                services_info = []

                if used_mcp_tools:
                    # 使用统一的格式化方法
                    mcp_tools_detail = self._format_mcp_tools_unified(used_mcp_tools)
                else:
                    # 如果没有使用的MCP工具，使用统计信息
                    stats = global_tools_info.get("stats", {})
                    mcp_count = stats.get('mcp_tools_count', 0)
                    services_info.append(f"  - 可用MCP工具: {mcp_count} 个")
                    mcp_tools_detail = "\n暂无可用MCP服务\n"
            else:
                logger.error("全局工具字典未初始化，无法获取MCP工具信息")
                return "\n📚 无法获取MCP工具信息，请检查配置或初始化全局工具字典"

            # 构建完整的MCP提示词
            mcp_guidance = f"""
# MCP工具调用方法：使用 'call_mcp_tool' 工具：调用具体的MCP功能
{mcp_tools_detail}
# MCP 工具调用规则：
1. 参数必须是有效的JSON字符串格式
2. 严格参考工具详情提供的服务名称、工具名称和参数内容必须完全匹配工具定义
3. 优先选择最适合用户需求的工具
4. 如果不确定参数格式，先使用 list_mcp_services 查看详细信息
5. 严格按照mcp工具定义的参数内容进行传参，不允许增加或修改参数
"""

            return mcp_guidance

        except Exception as e:
            print(f"❌ 生成MCP工具提示词失败: {e}")
            return ""

    def _format_mcp_tools_unified(self, used_mcp_tools: Dict[str, List[Dict]]) -> str:
        """从全局字典格式化MCP工具信息"""
        if not used_mcp_tools:
            return "\n📚 暂无可用的MCP工具\n"

        formatted_tools = "\n## 可用MCP工具详情\n"

        for service_name, tools in used_mcp_tools.items():
            formatted_tools += f"\n### 可用的MCP服务: {service_name}\n"

            if not tools:
                formatted_tools += "  - 暂无工具\n"
                continue

            for tool in tools:
                tool_name = tool.get('tool_name', 'unknown')
                description = tool.get('description', '无描述')
                parameters = tool.get('parameters', {})

                # 标准化工具信息格式
                formatted_tools += f"\n**工具名称**: `{tool_name}`\n"
                formatted_tools += f"**功能描述**: {description}\n"

                # 格式化参数信息
                if parameters:
                    formatted_tools += "**参数列表**:\n"
                    for param_name, param_config in parameters.items():
                        param_type = param_config.get('param_type', 'string')
                        param_desc = param_config.get('description', '')
                        is_required = param_config.get('is_required', False)

                        required_mark = "✅ 必需" if is_required else "⚪ 可选"
                        formatted_tools += f"  - `{param_name}` ({param_type}) - {required_mark}\n"
                        if param_desc:
                            formatted_tools += f"    描述: {param_desc}\n"
                else:
                    formatted_tools += "**参数列表**: 无参数\n"

                formatted_tools += "\n---\n"

        return formatted_tools

    def _load_mcp_tools_info(self) -> Dict[str, Any]:
        """
        加载MCP工具详细信息，优先使用全局工具字典
        """
        try:
            # 如果全局工具字典已初始化，优先使用
            if toolDictConfig.is_initialized():
                print("📚 使用全局工具字典加载MCP工具信息")
                return self._load_mcp_info_from_global_dict()

        except Exception as e:
            print(f"❌ 加载MCP工具信息失败: {str(e)}")
            return {
                'services': [],
                'tools_count': 0,
                'services_count': 0,
                'detail_tools': [],
                'error': str(e)
            }

    def _load_mcp_info_from_global_dict(self) -> Dict[str, Any]:
        """从全局工具字典加载MCP信息"""
        mcp_tools_dict = toolDictConfig.get_mcp_tools_dict()

        # 按服务分组工具
        services_map = {}
        total_tools = 0

        for tool_key, tool_info in mcp_tools_dict.items():
            mcp_service = tool_info.get('mcp_service', 'unknown')
            tool_name = tool_info.get('tool_name', 'unknown')

            if mcp_service not in services_map:
                services_map[mcp_service] = {
                    'mcp_name': mcp_service,
                    'tools': [],
                    'tools_count': 0
                }

            services_map[mcp_service]['tools'].append({
                'tool_name': tool_name,
                'parameters': tool_info.get('parameters', {}),
                'description': tool_info.get('description', ''),
                'tool_key': tool_key
            })
            services_map[mcp_service]['tools_count'] += 1
            total_tools += 1

        services_list = list(services_map.values())

        print(f"📚 从全局字典加载了 {len(services_list)} 个MCP服务，{total_tools} 个工具")

        return {
            'services': services_list,
            'tools_count': total_tools,
            'services_count': len(services_list),
            'detail_tools': list(mcp_tools_dict.values()),
            'source': 'global_dict'
        }

    def _create_mcps_from_global_dict(self, mcp_list: List[Union[str, Dict[str, Any]]]) -> List[str]:
        """
        从全局工具字典创建MCP连接列表，返回连接成功的服务器名称
        """
        if not mcp_list:
            return []

        # 检查是否启用了MCP功能
        if hasattr(self, '_mcp_enabled') and not self._mcp_enabled:
            print("⚪ MCP功能未启用，跳过MCP连接创建")
            return []

        try:
            print(f"🔌 创建MCP连接列表，输入MCP数量: {len(mcp_list)}")

            db = next(get_db_session())

            try:
                # 根据当前事件循环状态选择执行方式
                try:
                    loop = asyncio.get_event_loop()
                    if loop.is_running():
                        with concurrent.futures.ThreadPoolExecutor() as executor:
                            future = executor.submit(
                                lambda: asyncio.run(MCPFactory.create_mcps_from_list(mcp_list, db))
                            )
                            connected_servers = future.result(timeout=30)
                    else:
                        # 没有运行的事件循环，直接运行
                        connected_servers = loop.run_until_complete(MCPFactory.create_mcps_from_list(mcp_list, db))
                except RuntimeError:
                    # 没有事件循环，创建新的
                    connected_servers = asyncio.run(MCPFactory.create_mcps_from_list(mcp_list, db))

                print(f"🔌 MCP连接创建完成，成功连接 {len(connected_servers)} 个服务器")
                return connected_servers

            finally:
                db.close()

        except Exception as e:
            print(f"❌ 从全局字典创建MCP连接失败: {e}")
            return []

    def get_mcp_tools_info_from_global_dict(self) -> Dict[str, Any]:
        """
        从全局工具字典获取MCP工具信息
        """
        try:
            if not toolDictConfig.is_initialized():
                return {
                    "initialized": False,
                    "mcp_tools": {},
                    "error": "全局工具字典未初始化"
                }

            mcp_tools_dict = toolDictConfig.get_mcp_tools_dict()

            # 现在mcps是连接的服务器名称列表
            connected_servers = getattr(self, 'mcps', []) or []

            # 从mcp_client获取实际连接的服务器信息
            used_mcp_tools = {}
            if connected_servers:
                # 从全局工具字典中查找相关工具信息
                for server_name in connected_servers:
                    print(f"🔌 正在查找服务器 {server_name} 的MCP工具")
                    server_tools = []
                    for tool_key, tool_info in mcp_tools_dict.items():
                        # 检查工具是否属于当前服务器
                        if tool_info.get('mcp_service') == server_name:
                            server_tools.append({
                                'tool_name': tool_info.get('tool_name'),
                                'parameters': tool_info.get('parameters', {}),
                                'description': tool_info.get('description', ''),
                                'tool_key': tool_key
                            })
                    if server_tools:
                        used_mcp_tools[server_name] = server_tools

            return {
                "initialized": True,
                "used_mcp_tools": used_mcp_tools,
                "connected_servers": connected_servers,
                "available_mcp_tools_count": len(mcp_tools_dict)
            }

        except Exception as e:
            return {
                "initialized": False,
                "error": str(e)
            }

    def get_config(self):
        pass


def with_mcp_capability(cls):
    """
    装饰器函数，为类添加MCP功能
    
    Usage:
        @with_mcp_capability
        class MyAgent(BaseAgent):
            pass
    """

    # 检查被装饰的类是否有必要的基类方法
    required_attrs = ['tools', 'mcps']
    for attr in required_attrs:
        if not hasattr(cls, attr) and not any(hasattr(base, attr) for base in inspect.getmro(cls)):
            print(f"⚠️ 警告: 被装饰的类 {cls.__name__} 可能缺少必要的属性 {attr}")

    # 创建新的类，继承原类和MCP混入
    class MCPEnabledClass(cls, MCPMixin):
        def __init__(self, *args, **kwargs):
            # 检查是否有 mcp_list 参数且不为空
            mcp_list = kwargs.get('mcp_list', [])
            self._mcp_enabled = True

            # 调用父类初始化
            super().__init__(*args, **kwargs)

            # 根据mcp_list决定是否启用MCP功能
            if self._mcp_enabled:
                print(f"🎯 {cls.__name__} 已启用MCP功能，MCP数量: {len(getattr(self, 'mcps', []))}")
            else:
                print(f"⚪ {cls.__name__} 未启用MCP功能 (mcp_list为空)")

        def get_enhanced_system_prompt(self) -> str:
            """
            获取增强后的系统提示词，包含MCP工具信息
            
            Returns:
                包含MCP工具信息的系统提示词
            """
            base_prompt = getattr(self, 'sys_prompt', '')

            # 只有在启用MCP功能时才添加MCP提示词
            if self._mcp_enabled:
                mcp_prompt = self.get_mcp_tools_prompt_text()
                if mcp_prompt:
                    return f"{base_prompt}\n{mcp_prompt}"

            return base_prompt

        def get_mcp_tools_prompt_text(self) -> str:
            """重写方法，只有在启用MCP时才返回提示词"""
            if not self._mcp_enabled:
                return ""
            return super().get_mcp_tools_prompt_text()

        def get_mcp_tools_info_from_global_dict(self) -> Dict[str, Any]:
            """重写方法，只有在启用MCP时才返回信息"""
            if not self._mcp_enabled:
                return {
                    "initialized": False,
                    "mcp_enabled": False,
                    "message": "MCP功能未启用"
                }
            return super().get_mcp_tools_info_from_global_dict()

        def get_config(self) -> Dict[str, Any]:
            """重写get_config方法，添加MCP信息"""
            config = super().get_config() if hasattr(super(), 'get_config') else {}

            # 添加MCP配置信息
            if self._mcp_enabled:
                mcp_info = self.get_mcp_tools_info_from_global_dict()
                config.update({
                    'mcp_enabled': True,
                    'mcp_count': len(getattr(self, 'mcps', [])),
                    'mcp_tools_info': mcp_info
                })
            else:
                config.update({
                    'mcp_enabled': False,
                    'mcp_count': 0,
                    'mcp_tools_info': {"message": "MCP功能未启用"}
                })

            return config

    # 保持原类名
    MCPEnabledClass.__name__ = cls.__name__
    MCPEnabledClass.__qualname__ = cls.__qualname__

    return MCPEnabledClass


# 别名装饰器，更简洁的使用方式
mcp_enabled = with_mcp_capability
